import Long from 'long';
import {WL} from './weilapb'
import type {
    WL_IDbAudioData,
    WL_IDbMsgData,
    WL_IDbPttData,
    WL_IDbService,
    WL_IDbServiceSession,
    WL_IDbServiceSessionInfo,
    WL_IDbServiceStaff,
    WL_IDbServiceStaffInfo,
    WL_IDbSession,
    WL_IDbUserInfo
} from "./weilapb_external_data";

import {
    WL_IDbMsgDataStatus,
    WL_IDbMsgDataType,
} from "./weilapb_external_data";

import {TextMsgDataParser} from "./weilapb_textmsg_parser";
import CryptoJS from 'crypto-js'
import {calculateOpusDataFrame} from "@/core/weila_utils";
import {Weila_MemDB} from "@/mem_store/weila_db";
import axios from "axios";

export function hexStr2Uint8Array(hexStr: string): Uint8Array|undefined {
    if (hexStr.length % 2 == 0) {
        const hexArray = hexStr.match(/.{1,2}/g);
        if (hexArray) {
            return Uint8Array.from(hexArray.map(v => parseInt(v, 16)));
        }
    }

    return undefined;
}

export function uint8Array2HexStr(arrayBuffer: Uint8Array): string {
    if (arrayBuffer.length) {
        return arrayBuffer.reduce((previousValue, currentValue) => previousValue + currentValue.toString(16).padStart(2, '0'), '');
    }

    return '';
}

export function getStringFromBase64(base64Str: string): string {
    let base64Array = CryptoJS.enc.Base64.parse(base64Str);
    return base64Array.toString(CryptoJS.enc.Utf8);
}

// http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt

/* utf.js - UTF-8 <=> UTF-16 convertion
 *
 * Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
 * Version: 1.0
 * LastModified: Dec 25 1999
 * This library is free.  You can redistribute it and/or modify it.
 */

export function uint8Array2Utf8Str(arrayBuffer: Uint8Array): string {
    let out, i, len, c;
    let char2, char3;

    out = "";
    len = arrayBuffer.length;
    i = 0;
    while(i < len) {
        c = arrayBuffer[i++];
        switch(c >> 4)
        {
            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
            // 0xxxxxxx
            out += String.fromCharCode(c);
            break;
            case 12: case 13:
            // 110x xxxx   10xx xxxx
            char2 = arrayBuffer[i++];
            out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
            break;
            case 14:
                // 1110 xxxx  10xx xxxx  10xx xxxx
                char2 = arrayBuffer[i++];
                char3 = arrayBuffer[i++];
                out += String.fromCharCode(((c & 0x0F) << 12) |
                    ((char2 & 0x3F) << 6) |
                    ((char3 & 0x3F) << 0));
                break;
        }
    }

    return out;
}

export function getPbResultCodeMassage(resultCode: number): string {
    let msg = '';
    switch (resultCode) {
        case WL.Service.ResultCode.RESULT_SUCCESS: {
            msg = "成功";
        }break;

        case WL.Service.ResultCode.RESULT_FAILURE: {
            msg = "失败";
        }break;

        case WL.Service.ResultCode.RESULT_DISCONNECT: {
            msg = "连接中断";
        }break;

        case WL.Service.ResultCode.RESULT_NO_MSG_SERVER: {
            msg = "未连接消息服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_DB_SERVER: {
            msg = "未连接数据服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_CACHE_SERVER: {
            msg = "未连接缓存服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_LOGIN_SERVER: {
            msg = "未连接登录服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_ROUTE_SERVER: {
            msg = "未连接路由服务器";
        }break;

        case WL.Service.ResultCode.RESULT_DB_EXCEPTION: {
            msg = "数据库异常";
        }break;

        case WL.Service.ResultCode.RESULT_CACHE_EXCEPTION: {
            msg = "缓存异常";
        }break;

        case WL.Service.ResultCode.RESULT_SERVER_MAINTENANCE: {
            msg = "服务器维护中";
        }break;

        case WL.Service.ResultCode.RESULT_SERVER_EXCEPTION: {
            msg = "服务器异常";
        }break;


        case WL.Service.ResultCode.RESULT_PARAM_INVALID: {
            msg = "参数错误";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_NOT_SUPPORT: {
            msg = "请求不支持";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_LIMITED: {
            msg = "请求受限";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_INVALID: {
            msg = "请求已过期";
        }break;

        case WL.Service.ResultCode.RESULT_VERSION_TOO_OLD: {
            msg = "APP版本太旧,需要更新";
        }break;

        case WL.Service.ResultCode.RESULT_BLACKLIST_LIMITED: {
            msg = "您已被拉黑";
        }break;

        case WL.Service.ResultCode.RESULT_AUTH_INVALID: {
            msg = "认证无效";
        }break;

        case WL.Service.ResultCode.RESULT_PERMIT_LIMITED: {
            msg = "权限受限";
        }break;

        case WL.Service.ResultCode.RESULT_DATA_NOT_EXIST: {
            msg = "数据不存在";
        }break;

        case WL.Service.ResultCode.RESULT_DATA_INVALID: {
            msg = "数据无效";
        }break;

        case WL.Service.ResultCode.RESULT_VERIFICATION_CODE_ERROR: {
            msg = "验证码错误";
        }break;

        case WL.Service.ResultCode.RESULT_TOKEN_INVALID: {
            msg = "授权失效";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_FREQUENTLY: {
            msg = "请求太频繁";
        }break;

        case WL.Service.ResultCode.RESULT_NUMBER_RESOURCE_USE_UP: {
            msg = "号码资源耗尽";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_TIMEOUT: {
            msg = "请求超时";
        }break;

        case WL.Service.ResultCode.RESULT_TRANSMIT_TIMEOUT: {
            msg = "网络传输超时";
        }break;

        case WL.Service.ResultCode.RESULT_APP_ILLEGAL: {
            msg = "应用未授权,请从官方渠道获取";
        }break;

        case WL.Service.ResultCode.RESULT_PHONE_DUPLICATE: {
            msg = "手机号已被使用";
        }break;

        case WL.Service.ResultCode.RESULT_PHONE_INVALID: {
            msg = "手机号无效";
        }break;

        case WL.Service.ResultCode.RESULT_PHONE_HAS_BEEN_BANNED: {
            msg = "手机号被封禁";
        }break;

        case WL.Service.ResultCode.RESULT_PASSWORD_ERROR: {
            msg = "密码错误";
        }break;

        case WL.Service.ResultCode.RESULT_SEND_VERIFICATION_CODE_FAIL: {
            msg = "发送验证码失败";
        }break;

        //Login Error
        case WL.Service.ResultCode.RESULT_LOGIN_FORBID_IP: {
            msg = "用户IP被封 从forbidDuration获取剩余时长(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_FORBID_USER: {
            msg = "用户被封号 从forbidDuration获取剩余时长(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_PASSWORD_ERROR_TOO_TIMES: {
            msg = "密码输入错误次数太多,请待系统解封后再试(默认30分钟后才可登录) 从forbidDuration获取剩余时长(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_SYSTEM_FULL: {
            msg = "在线用户达到系统容量";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_VERIFYCODE_INVALID: {
            msg = "验证码无效";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_ACCOUNT_OR_PASSWD_ERROR: {
            msg = "账号或密码错误(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_HAS_BIND: {
            msg = "用户已绑定设备";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_BINDING: {
            msg = "设备绑定中";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_NOT_BIND: {
            msg = "未绑定分机";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_LAWLESSNESS: {
            msg = "非法设备(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_LICENSE_LIMITED: {
            msg = "许可证用完(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_ACCOUNT_ERROR: {
            msg = "设备账号错误(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_PASSWORD_ERROR: {
            msg = "设备密码错误(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_OFFLINE: {
            msg = "设备不在线";
        }break;

        //User Error
        case WL.Service.ResultCode.RESULT_USER_NOT_EXIST: {
            msg = "用户不存在";
        }break;

        case WL.Service.ResultCode.RESULT_USER_PERIPHERAL_UNAUTHORIZED: {
            msg = "外设未授权";
        }break;

        case WL.Service.ResultCode.RESULT_USER_PERIPHERAL_REPLICATED: {
            msg = "外设被复制";
        }break;

        case WL.Service.ResultCode.RESULT_USER_PERIPHERAL_MULTIDEVICE: {
            msg = "外设在多设备上使用";
        }break;

        case WL.Service.ResultCode.RESULT_USER_OFFLINE: {
            msg = "用户不在线";
        }break;

        //Friend Error
        case WL.Service.ResultCode.RESULT_FRIEND_NOT_FRIEND: {
            msg = "不是好友";
        }break;

        case WL.Service.ResultCode.RESULT_FRIEND_INVITE_NOT_EXIST: {
            msg = "好友邀请已过期";
        }break;

        case WL.Service.ResultCode.RESULT_FRIEND_IS_BLACKLIST: {
            msg = "您已被对方加入黑名单  ";
        }break;

        case WL.Service.ResultCode.RESULT_FRIEND_SHIELD_OPEN: {
            msg = "好友已开启消息屏蔽   ";
        }break;


        //Group Error
        case WL.Service.ResultCode.RESULT_GROUP_NOT_EXIST: {
            msg = "群组不存在";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_ACCESS_LIMITED: {
            msg = "访问受限,请明天再试(被踢或被封)";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_YOU_ARE_NOT_OWNER: {
            msg = "您不是群主";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_YOU_ARE_NOT_ADMIN: {
            msg = "您不是群管理员";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBERS_FULL: {
            msg = "成员数达到上限";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_NUMBER_USEUP: {
            msg = "群组号耗尽";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BROADCAST_EXIST: {
            msg = "群组广播已存在";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BROADCAST_NOEXIST: {
            msg = "群组广播不存在";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_PASSWORD_ERROR: {
            msg = "群密码错误";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_OWNER_FULL: {
            msg = "您创建的群组数达到上限";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BURST_OCCUPY: {
            msg = "话权被占用";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_USER_NOT_MEMBER: {
            msg = "用户不是群成员";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_LIMIT_MAX: {
            msg = "群成员上限达到最大值";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_IS_ADMIN: {
            msg = "不能对管理员进行操作";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_USER_IN_BLACKLIST: {
            msg = "用户被加入群黑名单";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_OWNER_CANNOT_EXIT: {
            msg = "群主不能退群,请先转让群主或直接删除群";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_YOU_ARE_SHUTUP: {
            msg = "你已被禁言";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_SHUTUP: {
            msg = "群成员被禁言";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_IS_OWNER: {
            msg = "不能对群主进行操作";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BURST_REVOKE: {
            msg = "话权被回收";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_IS_EXTENSION: {
            msg = "不能对设备用户进行操作";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_COUNT_LIMIT: {
            msg = "加群数量达到上限";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_HAS_EXTENSION: {
            msg = "成员中存在设备用户";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_OWNER_CANNOT_EXTENSION: {
            msg = "群主不能是设备用户";
        }break;


        //Session Error
        case WL.Service.ResultCode.RESULT_SESSION_BURST_MONITOR: {
            msg = "设备正在被其他人监听,请稍后再试";
        }break;

        //Room Error
        case WL.Service.ResultCode.RESULT_ROOM_HAS_EXIST: {
            msg = "房间已存在";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_NOT_EXIST: {
            msg = "房间不存在";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_LOCK: {
            msg = "房间处于锁定状态";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_SPEAKING: {
            msg = "有人在讲话";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_CHANGE_CHARGE_LIMITED: {
            msg = "房间未锁定或有访客不允许修改计费";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_HONORED_GUEST_PERMIT: {
            msg = "只有嘉宾才允许当前操作";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_NOT_ENTRY: {
            msg = "用户未进入房间";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_YOU_ARE_HONORED_GUEST: {
            msg = "您已经是嘉宾";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_HONORED_GUEST_FULL: {
            msg = "嘉宾数量达到上限";
        }break;

        //Business Error
        case WL.Service.ResultCode.RESULT_BUSINESS_SERVICE_CLOSED: {
            msg = "服务已关闭";
        }break;

        case WL.Service.ResultCode.RESULT_BUSINESS_STAFF_INVALID: {
            msg = "不是客服号";
        }break;

        case WL.Service.ResultCode.RESULT_BUSINESS_STAFF_NOT_ONLINE: {
            msg = "客服不在线";
        }break;

        case WL.Service.ResultCode.RESULT_BUSINESS_STAFF_BUSY: {
            msg = "客服忙";
        }break;

        default: {
            msg = '';
        }
    }
    return msg;
}

export function getResultCodeFromError(errorMsg: string): number {
    const pattern = /RET_CODE:(.*)-MESSAGE:/i;
    const result = errorMsg.match(pattern);
    if (result) {
        if (result.length > 1) {
            return parseInt(result[1]);
        }
    }

    return -1;
}

export function convertFromUserRaw(userRaw: WL.Common.IUserInfo|undefined|null): WL_IDbUserInfo {
    const userInfo = {} as WL_IDbUserInfo;
    if (userRaw == undefined) {
        userInfo.userId = 0;
        userInfo.avatar = '';
        userInfo.countryCode = '';
        userInfo.created = 0;
        userInfo.email = ""
        userInfo.nick = "";
        userInfo.pinyinName = '';
        userInfo.phone = "";
        userInfo.sex = 0;
        userInfo.signature = "";
        userInfo.status = 0;
        userInfo.userType = 0;
        userInfo.weilaNum = '';
    }else {
        userInfo.userId = userRaw.userId || 0;
        userInfo.avatar = userRaw.avatar || '';
        userInfo.countryCode = userRaw.countryCode || '';
        userInfo.created = Long.fromValue(userRaw.created || 0).toNumber();
        userInfo.email = userRaw.email || ""
        userInfo.nick = userRaw.nick || "";
        userInfo.pinyinName = '';
        userInfo.phone = userRaw.phone || "";
        userInfo.sex = userRaw.sex || 0;
        userInfo.signature = userRaw.signature || "";
        userInfo.status = userRaw.status || 0;
        userInfo.userType = userRaw.type || 0;
        userInfo.weilaNum = userRaw.number || '';
    }

    return userInfo;
}

export function convertFromMsgDataRaws(msgDataRaws: WL.Session.IMsgData[], myUserId: number): WL_IDbMsgData[] {
    const count = msgDataRaws.length;
    const msgDatas: WL_IDbMsgData[] = [];

    for (let i = 0; i < count; i++) {
        const msgData: WL_IDbMsgData = {} as WL_IDbMsgData;
        msgData.created = Long.fromValue(msgDataRaws[i].created || 0).toNumber();
        msgData.msgId = msgDataRaws[i].msgId || 0;
        if ((msgDataRaws[i].sessionType == WL.Common.SessionType.SESSION_TYPE_SINGLE ||
                msgDataRaws[i].sessionType == WL.Common.SessionType.SESSION_TYPE_CORP_SINGLE)
            && msgDataRaws[i].senderId != myUserId) {
            msgData.senderId = msgDataRaws[i].senderId || 0;
            msgData.sessionId = (msgDataRaws[i].senderId || 0).toString(10);
        } else {
            msgData.senderId = msgDataRaws[i].senderId || 0;
            msgData.sessionId = (msgDataRaws[i].sessionId !== undefined) ? msgDataRaws[i].sessionId!.toString(10) : "";
        }
        msgData.sessionType = msgDataRaws[i].sessionType || 0;
        msgData.autoReply = msgDataRaws[i].autoReply || 0;
        msgData.tag = msgDataRaws[i].tag || "";
        msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_READ;
        msgData.combo_id = getMsgDataIdByCombo(msgData, 0);

        switch (msgDataRaws[i].msgType) {
            case WL.Session.MessageType.MSG_TYPE_TEXT: {
                const textMsgData = TextMsgDataParser.decodeSessionTextMsg(msgDataRaws[i].textData || "");
                if (textMsgData !== undefined) {
                    msgData.msgType = textMsgData.msgType;
                    msgData.textData = textMsgData.textData;
                    msgData.location = textMsgData.location;
                    msgData.fileInfo = textMsgData.fileInfo;
                    msgData.command = textMsgData.command;
                } else {
                    msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_ERR;
                }
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_PTT: {
                msgData.msgType = WL_IDbMsgDataType.WL_DB_MSG_DATA_PTT_TYPE;
                msgData.pttData = {} as WL_IDbPttData;
                msgData.pttData.data = (msgDataRaws[i].pttData && msgDataRaws[i].pttData!.opusData) ? msgDataRaws[i].pttData!.opusData!.payload || new Uint8Array() : new Uint8Array();
                msgData.pttData.frameCount = (msgDataRaws[i].pttData && msgDataRaws[i].pttData!.opusData) ? msgDataRaws[i].pttData!.opusData!.frameCount || 0 : 0;
                msgData.pttData.seq = msgDataRaws[i].pttData ? msgDataRaws[i].pttData!.seq || 0 : 0;
                msgData.pttData.seqInPackage = msgDataRaws[i].pttData ? msgDataRaws[i].pttData!.packageSeq || 0 : 0;
                msgData.pttData.mark = msgDataRaws[i].pttData ? msgDataRaws[i].pttData!.marker || 0 : 0;
                msgData.pttData.sourceType = msgDataRaws[i].pttData ? msgDataRaws[i].pttData!.source || 0 : 0;
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_AUDIO: {
                msgData.msgType = WL_IDbMsgDataType.WL_DB_MSG_DATA_AUDIO_TYPE;
                msgData.audioData = {} as WL_IDbAudioData;
                msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_NEW

                if (msgDataRaws[i].audioData) {
                    if (msgDataRaws[i].audioData!.payload && msgDataRaws[i].audioData!.payload!.length > 0) {
                        msgData.audioData.data = (msgDataRaws[i].audioData ? msgDataRaws[i].audioData!.payload || new Uint8Array() : new Uint8Array()).slice(0);
                        msgData.audioData.frameCount = calculateOpusDataFrame(msgData.audioData.data);
                    } else if (msgDataRaws[i].audioData!.url && msgDataRaws[i].audioData!.url !== '') {
                        msgData.audioData.audioUrl = msgDataRaws[i].audioData!.url || "";
                        const match = msgData.audioData.audioUrl.match(/.*\?duration=(\d+)/);
                        msgData.audioData.frameCount = 0;
                        if (match && match.length > 1) {
                            msgData.audioData.frameCount = parseInt(match[1]) * 50;
                        }
                    } else {
                        msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_ERR;
                    }
                } else {
                    msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_ERR;
                }
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_SERVICE: {
                msgData.msgType = WL_IDbMsgDataType.WL_DB_MSG_DATA_SERVICE_TYPE;
                msgData.serviceData = msgDataRaws[i].serviceData!;
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_SWITCH: {
                msgData.msgType = WL_IDbMsgDataType.WL_DB_MSG_DATA_SWITCH_TYPE;
                msgData.switchData = msgDataRaws[i].switchData!.serviceData || "";
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_REVOCATION: {
                msgData.msgType = WL_IDbMsgDataType.WL_DB_MSG_DATA_WITHDRAW_TYPE;
                msgData.withdrawMsgId = msgDataRaws[i].revocationMsgId!;
            }
            break;

            default: {
                msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_ERR;
            }
            break;
        }

        if (msgData.status != WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_ERR) {
            msgDatas.push(msgData);
        }
    }

    return msgDatas;
}

export function getMsgDataIdByCombo(msgData: WL_IDbMsgData, seq: number): string {
    if (msgData) {
        return `${msgData.sessionId}_${msgData.sessionType}_${msgData.msgId}_${seq}`;
    }

    return ''
}

export function convertFromSessionRaw(sessionRaws: WL.Session.ISessionInfo[], loginUserId: number): WL_IDbSession[] {
    const sessionCount = sessionRaws.length;
    const sessions: WL_IDbSession[] = [];
    for (let i = 0; i < sessionCount; i++) {
        let session = {} as WL_IDbSession;
        session.combo_id_type = sessionRaws[i].sessionId!.toString(10) + "_" + sessionRaws[i].sessionType;
        session.sessionId = sessionRaws[i].sessionId !== null && sessionRaws[i].sessionId !== undefined ? sessionRaws[i].sessionId!.toString(10) : '';
        session.sessionType = sessionRaws[i].sessionType || 0;
        session.readMsgId = sessionRaws[i].readMsgId || 0;
        session.latestUpdate = Long.fromValue(sessionRaws[i].latestUpdated || 0).toNumber();
        if (sessionRaws[i].latestMsgData) {
            const msgDatas: WL_IDbMsgData[] = convertFromMsgDataRaws([sessionRaws[i].latestMsgData!], loginUserId);
            if (msgDatas.length) {
                session.lastMsgId = msgDatas[0].msgId;
            }
        }

        sessions.push(session);
    }

    return sessions;
}

export function convertFromServiceRaw(serviceRaw: WL.Business.IServiceAttribute): WL_IDbService {
    const service = {} as WL_IDbService;
    if (serviceRaw == undefined) {
        service.serviceId = 0;
        service.serviceNum = '';
        service.serviceClass = 0;
        service.serviceType = 0;
        service.avatar = "";
        service.intro = "";
        service.name = "";
        service.url = "";
        service.createdTime = Long.fromValue(0).toNumber();
    }else {
        service.serviceId = serviceRaw.id || 0;
        service.serviceNum = serviceRaw.number || '';
        service.serviceClass = serviceRaw.class || 0;
        service.serviceType = serviceRaw.type || 0;
        service.avatar = serviceRaw.avatar || "";
        service.intro = serviceRaw.intro || "";
        service.name = serviceRaw.name || "";
        service.url = serviceRaw.url || "";
        service.createdTime = Long.fromValue(serviceRaw.created || 0).toNumber();
    }
    return service;
}

export function convertFromServiceSessionRaw(serviceSession: WL.Business.IServiceSession): WL_IDbServiceSessionInfo {
    const serviceSessionInfo = {} as WL_IDbServiceSessionInfo;
    const userInfos: WL_IDbUserInfo[] = [];
    serviceSessionInfo.serviceSession = {} as WL_IDbServiceSession;
    serviceSessionInfo.service = convertFromServiceRaw(serviceSession.serviceAttribute!);
    serviceSessionInfo.extra = serviceSession.extra;
    serviceSessionInfo.staffs = [];
    const staffs = convertFromStaffRaws(serviceSession.staffAttributes!);

    if (serviceSession.staffAttributes) {
        serviceSession.staffAttributes!.map(value => {
            userInfos.push(convertFromUserRaw(value.userInfo!));
        });
    }

    serviceSessionInfo.staffs = staffs.map((value, index) => {
        const staffInfo = {} as WL_IDbServiceStaffInfo;
        const userIndex = userInfos.findIndex(v => {
            return v.userId == value.userId;
        });

        if (userIndex !== -1) {
            staffInfo.userData = userInfos[userIndex];
        }

        staffInfo.staff = value;
        return staffInfo;
    });
    serviceSessionInfo.customer = convertFromUserRaw(serviceSession.customerAttribute!.userInfo);
    serviceSessionInfo.serviceSession.serviceId = serviceSession.serviceAttribute!.id || 0;
    serviceSessionInfo.serviceSession.serviceStatus = serviceSession.status || 0;
    if (serviceSession.staffAttributes) {
        serviceSessionInfo.serviceSession.staffIds = serviceSession.staffAttributes!.map(value => {
            return value.userInfo!.userId!;
        });
    }else {
        serviceSessionInfo.serviceSession.staffIds = [];
    }
    serviceSessionInfo.serviceSession.customerId = serviceSession.customerAttribute!.userInfo!.userId || 0;
    serviceSessionInfo.serviceSession.createdTime = Long.fromValue(serviceSession.created || 0).toNumber();
    serviceSessionInfo.serviceSession.updatedTime = Long.fromValue(serviceSession.updated || 0).toNumber();

    return serviceSessionInfo;
}

export function convertFromStaffRaws(staffRaws: WL.Business.IStaffAttribute[]): WL_IDbServiceStaff[] {
    return staffRaws.map(value => {
        const dbStaff = {} as WL_IDbServiceStaff;
        dbStaff.userId = value.userInfo!.userId || 0;
        dbStaff.staffClass = value.class || 0;
        dbStaff.staffType = value.type || 0;
        dbStaff.admin = value.admin || 0;
        dbStaff.isOperator = value.operator == 1;
        dbStaff.createdTime = Long.fromValue(value.created || 0).toNumber();
        return dbStaff;
    });
}

export async function convertPttAudioToMedia(msgData: WL_IDbMsgData): Promise<WL_IDbMsgData> {
    try {
        const accessToken = Weila_MemDB.getInstance().getLoginToken();
        const res = await axios.post("/weila/audios/ptt2mp3?access-token=" + accessToken, {ptt_url: msgData.audioData!.audioUrl!});
        if (res.status == 200) {
            console.log("res", res.status, res.data);
            msgData.audioData!.audioUrl = res.data.data.mp3_url;
        }
        return msgData;
    }catch (e) {
        console.log("weila_convertPttAudioToUrl", e);
        return Promise.reject(e);
    }
}

export function getOpusDataFrameCount(pttData: Uint8Array): number {
    let frameCount = 0;
    let offset = 0;
    let sizeOfOpusData = 0;
    let codedDataList = null;

    while (offset < pttData.length) {
        const flag = pttData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(pttData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = pttData[offset] + 1;
            offset += 1;
        }

        offset += (sizeOfOpusData - 1);
        frameCount++;
    }

    return frameCount;
}
